package Calcule;

import scene.Facette3D;
import geometrie.Point;
/**
 * Calculer l'aire avec differents Methodes statiques, chaqu'un 
 * faire un algorithme distinct pour le faire.
 * @author Manuel
 * @author Marcos
 */
public class Rebouchage {
	/**
	 * Variable du methode iniMemCache()
	 */
	private static MemoireCache memCache;
	/**
	 * Stocker de valeurs(iterations) pour calculer le temps
	 * de process
	 */
	public static int compteAccessFonction; //Compteur d'acces a la fonction
	public static int compteReturnFonction; //Compteur de returns faites
	/**
	 * Reset des valeurs statiques a 0 de la clase Rebouchage
	 */
	public static void resetCompte() {
		compteAccessFonction = 0;
		compteReturnFonction = 0;
	}
	/**
	 * Calculer l'aire a partir du l'algorithme Solution recursive naive
	 * @param polygone Tableau de points
	 * @return l'aire calculee avec 3 points;
	 */
	public static double rebouchageTrouRecNaif(Point[] polygone) {
		compteAccessFonction++;	
		//On initialise des variables pour le tableau
		double i = 0;
		double j = polygone.length - 1;
		//On prendre la valeur de <k> entre i et j comme l'algorithm 'Binary Search'
			//Il n'y a pas d'importance claire pour prendre un valeur en specifique
		double k = (int) Math.ceil((i + j) / 2);
		//Condition de recursivite
		if (k != j && k != i) {
			//Creer des semi-tableaus
				//Tableau 1
			Point[] polygone1 = new Point[(int) (k - i + 1)];
			for (int h = 0; h < polygone1.length; h++)
				polygone1[h] = new Point(polygone[h]);
				//Tableau 2
			Point[] polygone2 = new Point[(int) (j - k + 1)];
			for (int h = 0; h < polygone2.length; h++)
				polygone2[h] = new Point(polygone[polygone2.length-1-h]);
			compteReturnFonction++;
			//Retourner Aire(1) + Aire(2) + Aire( P1, P2, P3)
			return (rebouchageTrouRecNaif(polygone2)
					+ rebouchageTrouRecNaif(polygone1) + Point.getAire(
					polygone[(int) i], polygone[(int) j], polygone[(int) k]));
		}
		//Cas base
		return 0.0;
	}
	
	/**
	 * Initialiser des valeurs pour Mem Cache. Dans cet cas,
	 * il y a besoin parse que c'est une variable static, on doit
	 * l'initialiser chaque fois.
	 * @param polygone Taille du tableau
	 */
	public static void iniMemCache(Point[] polygone){
		memCache= new MemoireCache(polygone.length); 
	}
	/**
	 * Calculer l'aire a partir du l'algorithme Solution 
	 * recursive avec memoire cache
	 * @param polygone Tableau de points
	 * @return l'aire calculee avec 3 points;
	 */
	public static double rebouchageTrouRecCache(Point[] polygone){
		compteAccessFonction++;
		//On initialise des variables pour le tableau
		int i = 0;
		int j = polygone.length -1;
		//On prendre la valeur de <k> entre i et j comme l'algorithm 'Binary Search'
			//Il n'y a pas d'importance claire pour prendre un valeur en specifique
		int k = (int) Math.ceil(((double)i+(double)j)/2.0);
		//Verifier si la valeur de l'aire a ete deja calcule
		if(!memCache.isComputed(i, k, j)){
			//Condition de recursivite
			if(k!=j && k != i){
				//Creer des semi-tableaus
					//Tableau 1
				Point[] polygone1 = new Point[k-i+1];
				for(int h=0;h<polygone1.length;h++)
					polygone1[h] = new Point(polygone[h]);	
					//Tableau 2
				Point[] polygone2 = new Point[j-k+1];
				for(int h=0;h<polygone2.length;h++)
					polygone2[h] = new Point(polygone[polygone2.length-1-h]);	
				//Stockee l'aire avec des points (Pi,Pj,Pk)
				memCache.setCache(i, k, j, Point.getAire(polygone[i], polygone[j], polygone[k]));
				compteReturnFonction++;
				//Retourner Aire(1) + Aire(2) + Aire stockee
				return rebouchageTrouRecCache(polygone1) + rebouchageTrouRecCache(polygone2) +memCache.getCache(i, k, j);
			}	
			//Cas base
			return 0.0;
		}
		//Retourner la valeur deja calcule
		return memCache.getCache(i,k,j);
	}
	/**
	 * Calculer l'aire a partir du l'algorithme Solution iterative
	 * @param polygone Tableau de points
	 * @return l'aire calculee avec 3 points;
	 */
	public static double rebouchageTrouIter(Point[] polygone) {
		compteAccessFonction++;
		//On initialise des variables pour le tableau
		double aire = 0;
		int n = polygone.length - 2;
		//Faire des iterations
		for (int i = 0; i < (n - n % 2) / 2; i++) {
			aire += Point
					.getAire(polygone[0], polygone[i + 1], polygone[i + 2]);
			compteReturnFonction++;
		}
		aire = aire * 2; // Ajouter l'autre cote de la forme
		// Ajouter le semi aire du triangle centree
		if (polygone.length % 2 == 1) {
			//Retourner l'aire calcule
			return (aire + Point.getAire(polygone[0],
					polygone[(polygone.length - 1) / 2],
					polygone[polygone.length - 1]));
		}
		//Retourner l'aire calcule
		return aire;
	}

}
